import { container, createRenderer as fnType, vnodeType, vnodeType_component } from "../runtime-core/index.d"
import { createRenderer } from "../runtime-core"


// 这个文件夹是 createRenderer 函数的DOM实现  （用户可以自行传入自定义实现，这里是默认的用于DOM的）


/**创建元素   详细类型注释查看ts类型 */
const createElement: fnType["createElement"] = (vnodeType: string) => {
    return document.createElement(vnodeType)
}
/**给DOM结点挂载属性  详细类型注释查看ts类型*/
const patchProp: fnType["patchProp"] = (el: container, key: string, preVal: any, nextVal: any) => {

    /**判断是否是以on开头，且首字母大写的 */
    const isOn = (key: string) => /^on[A-Z]/.test(key)

    if (isOn(key)) { //如果是事件的话

        const event = key.slice(2).toLowerCase()//去掉on，转小写，就是 addEventListener 的事件名了
        el.addEventListener(event, nextVal)

    } else {//如果是属性的话
        if (nextVal === undefined || nextVal === null) { //如果新prop为空，就删掉这个属性
            el.removeAttribute(key)
        } else { //不然就是设置  （可以是新增，也可以是修改）
            el.setAttribute(key, nextVal)
        }
    }
}
/**在指定结点前插入DOM元素  详细类型注释查看ts类型*/
const insert: fnType["insert"] = (child: container, parent: container, anchor: container | null) => {
    parent.insertBefore(child, anchor || null) // 调用DOM API 插入到指定元素前面，第一个参数是要被插入的元素，第二个参数是“在谁前面”
}
/**移除DOM元素 移除单个孩子   详细类型注释查看ts类型*/
const remove: fnType["remove"] = (child: container | null) => {
    /**拿到这个孩子的父节点 */
    const parent = child?.parentNode
    if (parent) {//在父级身上把它删了
        parent.removeChild(child)
    }
}
/**将元素的孩子设置为text   详细类型注释查看ts类型*/
const setElementText: fnType["setElementText"] = (el: container, text: string) => {
    el.textContent = text
}

/**默认的DOM渲染器 （createRenderer函数的DOM实现） */
const renderer = createRenderer({
    createElement,
    patchProp,
    insert,
    remove,
    setElementText
})


/**创建APP组件    真正的 createApp 函数在 src\runtime-core\createApp.ts 中，这里使用高阶函数产生了一个默认用DOM渲染器的createAPP
 * @param  rootComponent  根组件
 */
export function createApp(rootComponent: vnodeType_component) {
    return renderer.createApp(rootComponent)
}


export * from "../runtime-core"; //因为dom模块是runtime-core模块的上层，所以在这里导出core，而不是在src/index.ts导出